<script>
import { valueToLabel, valueToOption } from '@/utils/dictionary'
import virtualScrollBar from '@/components/virtualScrollBar'
import _ from 'lodash'
import Edit from './components/Edit'
import { addClass } from '@/utils/index.js'
export default {
  props: {
    // 是否页面进入后就请求数据
    immediately: {
      type: Boolean,
      default: true
    },
    // 表格的数据
    tableData: {
      type: Array,
      default: null
    },
    // 获取接口所需字段
    beforeRequest: {
      type: Function,
      default: () => {
        return {}
      }
    },
    // 获取数据的接口
    request: {
      type: Function,
      default: () => {
        return {}
      }
    },
    // 配置的字段
    column: {
      type: Array,
      default: () => []
    },
    // 是否需要loading层
    loading: {
      type: Boolean,
      default: true
    },
    // 是否需要翻页
    isPagination: {
      type: Boolean,
      default: true
    },
    // 分页配置
    pageInfo: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 是否需要虚拟滚动条
    isVirtualScrollBar: {
      type: Boolean,
      default: false
    },
    // 保存编辑后的数据按钮
    saveRowBtn: {
      type: Boolean,
      default: true
    },
    // 是否需要添加一条新数据按钮
    isAddRowBtn: {
      type: Boolean,
      default: false
    },
    // 是否删除新增数据按钮
    isRemoveRowBtn: {
      type: Boolean,
      default: true
    },
    // 限制添加的个数
    addRowLimit: {
      type: [String, Number],
      default: 1
    }
  },
  data() {
    return {
      pageSizes: [10, 20, 30],
      data: [],
      showLoading: false,
      filter: {
        pageNo: 1,
        pageSize: 10
      },
      pageTotal: 0, // 总条数
      isOperColumn: false, // 是否操作 编辑区域
      editRows: [], // 编辑区域操作时用于保存标识
      newRowsNum: 0 // 新增数据的个数
    }
  },
  computed: {
    // 表格区域是否可编辑
    isColumnEdit() {
      return this.column.some(e => e.edit)
    }
  },
  watch: {
    tableData: {
      handler(val) {
        if (val && val.length) {
          this.data = val
          if (this.isOperColumn) {
            this.isOperColumn = false
          } else {
            this.editRows = this.data.map(() => { return {} })
          }
        }
      },
      immediate: true
    }
  },
  updated() {
    // 解决表格错位问题
    if (this.$refs.table && this.$refs.table.doLayout) {
      this.$refs.table.doLayout()
    }
  },
  mounted() {
    this.intPage()
    this.immediately && this.query()
  },
  methods: {
    intPage() {
      this.filter = { ...this.filter, ...this.pageInfo }
      if (!this.pageSizes.includes(this.filter.pageSize)) {
        this.pageSizes.push(this.filter.pageSize)
        this.pageSizes.sort((a, b) => (a - b))
      }
    },
    // 获取数据
    query() {
      if (this.tableData) return
      const params = { ...this.beforeRequest(), ...this.filter }
      if (this.loading) this.showLoading = true
      this.request(params)
        .then(res => {
          const { success, data, totalCount } = res
          if (success) {
            this.data = data
            this.pageTotal = totalCount
          }
          this.$emit('afterRequest', data)
          // 对 editColumn组件进行初始化
          this.editRows = this.data.map(() => { return {} })
          this.showLoading = false
          setTimeout(() => {
            this.$refs.scrollbar.windowScroll()
          }, 200)
        })
        .catch(err => {
          console.error(err)
          this.showLoading = false
        })
    },
    // 刷新
    refresh() {
      this.filter.pageNo = 1
      this.query()
    },
    // 处理表格标题
    headerHandling(h, item, scope) {
      const { column } = scope
      if (item.slotHeader) {
        if (!_.isFunction(item.slotHeader)) {
          console.error('slotHeader必须是个函数')
          return
        }
        return item.slotHeader(scope, h)
      }
      let tips = () => ''
      if (item.tip && item.tip !== '') {
        tips = () => {
          return (
            <el-tooltip effect='dark' content={item.tip} placement='top'>
              <i class='el-icon-warning-outline' />
            </el-tooltip>
          )
        }
      }
      return (<span>{column.label} {tips()}</span>)
    },
    // 处理数据
    dataHandling(h, item, scope) {
      const { row, $index } = scope
      if (item.slot) {
        if (!_.isFunction(item.slot)) {
          console.error('slot必须是个函数')
          return
        }
        return item.slot(scope, h)
      }
      if (item.key === 'index') {
        return ($index + 1) + this.filter.pageSize * (this.filter.pageNo - 1)
      }
      // 配置颜色
      let color = null
      // 配置数据字典
      if (item.dict && item.dict.key) {
        const option = valueToOption(row[item.key], item.dict.key, item.dict.path)
        color = option?.color ? option.color : null
        if (color) {
          return <span style={{ color: color }}>{ valueToLabel(row[item.key], item.dict.key) }</span>
        }
        return valueToLabel(row[item.key], item.dict.key, item.dict.path)
      }
      if (color) {
        return <span style={{ color: color }}>{row[item.key]}</span>
      }
      return row[item.key]
    },
    // 分页
    handleCurrentChange(val) {
      if (this.filter.pageNo === val) {
        return
      }
      this.filter.pageNo = val
      this.query()
    },
    handleCurrentChangeSize(val) {
      this.filter.pageSize = val
      this.query()
    },
    // 添加一条新数据
    addColumn() {
      const newRows = this.editRows.filter((e) => e.isNewRow).length
      if (newRows >= this.addRowLimit) {
        this.$message.error(`单次最多只能新增${this.addRowLimit}条数据`)
        return
      }
      const params = {}
      const rows = {}
      this.column.forEach(e => {
        if (!e.edit) return
        params[e.key] = ''
        rows[e.key + 'Edit'] = true
        rows[e.key + 'Tag'] = false
        rows[e.key + 'Default'] = ''
        params.isNewRow = rows.isNewRow = true
        rows.isRowEdit = true
      })
      this.isOperColumn = true
      this.data.unshift(params)
      this.editRows.unshift(rows)
      this.newRowsNum = this.editRows.filter((e) => e.isNewRow).length
    },
    // 删除一条添加的数据
    removeColumn() {
      this.isOperColumn = true
      this.data.shift()
      this.editRows.shift()
      this.newRowsNum = this.editRows.filter((e) => e.isNewRow).length
    },
    // 保存编辑区域内容
    saveColumn() {
      return new Promise((resolve, reject) => {
        if (!this.editRows.some(e => e.isRowEdit)) {
          this.$message.error('暂无可保存的内容')
          return
        }
        const newRows = { 'add': [], 'edit': [], 'all': [] }
        // 数据处理
        this.data.forEach((e, i) => {
          if (this.editRows[i]?.isRowEdit) {
            this.editRows[i].isNewRow ? newRows.add.push(e) : newRows.edit.push(e)
          }
          newRows.all.push(e)
        })
        // 数据校验
        let verification = null
        for (const i in this.column) {
          const el = this.column[i]
          if (el.edit && el.edit.require) {
            const isError = newRows.add.some(e => !e[el.key]) || newRows.edit.some(e => !e[el.key])
            if (isError) {
              verification = { isError: isError, title: el.title, index: i }
              break
            }
          }
        }
        if (verification) {
          this.setValidate(verification.index)
          this.$message.error(`${verification.title}不能为空`)
          return
        }
        this.$emit('saveColumn', newRows)
        resolve(newRows)
      })
    },
    // 将验证失败的数据加入样式
    setValidate(index) {
      const table = this.$el.querySelectorAll('.el-table__row')
      for (const i in table) {
        if (typeof table[i] === 'object' && table[i] !== null && 'querySelectorAll' in table[i]) {
          const editBox = table[i].querySelectorAll('td')[index].querySelector('.edit-wrapper')
          const input = editBox.querySelector('.el-input__inner')
          if (input && !input.value) {
            addClass(editBox, 'error')
            break
          }
        }
      }
    },
    // 设置表头
    setTableColum(arr) {
      const _this = this
      return arr?.length ? arr.map((item, index) => {
        return (<el-table-column
          prop={item.key}
          type={item.type}
          label={item.title}
          align={item.align || 'center'}
          fixed={item.fixed || false}
          key={index}
          sortable={item.sortable || false}
          width={item.width}
          minWidth={item.minWidth}
          showOverflowTooltip={item.showOverflowTooltip || false}
          scopedSlots={['selection', 'index', 'expand'].includes(item.type) ? {} : {
            header(scope) {
              // eslint-disable-next-line no-undef
              return _this.headerHandling(h, item, scope)
            },
            default(scope) {
              return item.edit ? (
                // eslint-disable-next-line no-undef
                <Edit column={item} row={scope.row} editRow={_this.editRows[scope.$index] || {}} >{ _this.dataHandling(h, item, scope) }</Edit>
              // eslint-disable-next-line no-undef
              ) : _this.dataHandling(h, item, scope)
            }
          }}
        >
          {_this.setTableColum(item.children)}
        </el-table-column>
        )
      }) : null
    }
  },
  render(h) {
    const _this = this
    const directives = [{ name: 'loading', value: this.showLoading }]
    return (
      <div class='config-table'
        {...{ directives }}
      >
        { _this.isColumnEdit && _this.saveRowBtn ? <el-button type='primary' size='small' class='mb-10' onClick={() => this.saveColumn() }>保存</el-button> : null }
        { _this.isColumnEdit && _this.isAddRowBtn ? <el-button type='primary' size='small' class='mb-10' onClick={() => this.addColumn() }>新增</el-button> : null }
        { _this.newRowsNum > 0 && _this.isRemoveRowBtn ? <el-button type='primary' size='small' class='mb-10' onClick={() => this.removeColumn() }>取消</el-button> : null }
        <el-table
          size='medium'
          {...{
            props: _this.$attrs,
            on: _this.$listeners
          }}
          data={_this.data}
        >
          {_this.setTableColum(_this.column)}
        </el-table>
        {this.data.length > 0 && this.isVirtualScrollBar ? <virtualScrollBar ref='scrollbar' /> : null}
        {this.isPagination && this.pageTotal > 0 ? (<el-pagination
          background
          onCurrent-change={val => { _this.handleCurrentChange(val) }}
          onSize-change={val => { _this.handleCurrentChangeSize(val) }}
          current-page={_this.filter.pageNo}
          page-size={_this.filter.pageSize}
          page-sizes={_this.pageSizes}
          layout='total, sizes, prev, pager, next, jumper'
          total={_this.pageTotal}
        >
        </el-pagination>) : null}
      </div>
    )
  }
}
</script>
<style lang="scss">
.config-table {
  margin-top: 10px;

  .el-pagination {
    padding: 10px 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #fff;
  }

  .el-table__fixed-right::before {
    background-color: initial;
  }
}
</style>
